package ace.module.upms.core.impl.manager.impl;

import ace.cmp.core.constants.CoreConstant;
import ace.cmp.core.utils.SystemClockUtils;
import ace.cmp.data.spring.data.jdbc.querydsl.rsql.core.manager.spring.AbstractSpringDtoManager;
import ace.module.upms.api.model.dto.UpmsRoleAccountDto;
import ace.module.upms.core.impl.dao.entity.QUpmsRoleAccount;
import ace.module.upms.core.impl.dao.entity.UpmsRoleAccount;
import ace.module.upms.core.impl.dao.repository.UpmsRoleAccountRepository;
import ace.module.upms.core.impl.manager.UpmsRoleAccountManager;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Ops;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.Expressions;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * 角色与账户关联 spring data jdbc querydsl rsql manager implement.
 *
 * @author Caspar
 */
@Slf4j
@AllArgsConstructor
@Component
public class UpmsRoleAccountManagerImpl
    extends AbstractSpringDtoManager<UpmsRoleAccount, Long, UpmsRoleAccountDto>
    implements UpmsRoleAccountManager {

  private final UpmsRoleAccountRepository upmsRoleAccountRepository;

  @Override
  public List<UpmsRoleAccount> getByRoleIdAndIamAccountIdEntryAndDeleteFlagIsFalse(Long upmsAppId, List<SimpleEntry<Long, Long>> roleIdWithAccountIdEntryList) {
    return this.upmsRoleAccountRepository.queryMany(sqlQuery -> {
      QUpmsRoleAccount qUpmsRoleAccount = QUpmsRoleAccount.upmsRoleAccount;
      List<Predicate> predicates = new ArrayList<>();
      for (SimpleEntry<Long, Long> roleIdWithAccountIdEntry : roleIdWithAccountIdEntryList) {
        Long roleId = roleIdWithAccountIdEntry.getKey();
        Long iamAccountId = roleIdWithAccountIdEntry.getValue();
        predicates.add(
            Expressions.predicate(
                Ops.WRAPPED,
                qUpmsRoleAccount.roleId.eq(roleId),
                qUpmsRoleAccount.iamAccountId.eq(iamAccountId)
            )
        );
      }
      Predicate predicate = ExpressionUtils.anyOf(predicates);
      return sqlQuery
          .select(qUpmsRoleAccount)
          .from(qUpmsRoleAccount)
          .where(qUpmsRoleAccount.upmsAppId.eq(upmsAppId))
          .where(qUpmsRoleAccount.deleteFlag.eq(CoreConstant.DELETE_FLAG_NOT))
          .where(predicate);
    });
  }

  @Override
  public boolean noneMatch(List<UpmsRoleAccount> roleAccounts, Long upmsRoleId, Long iamAccountId) {
    return roleAccounts.stream()
        .noneMatch(roleAccount ->
            roleAccount.getIamAccountId().equals(iamAccountId) &&
                roleAccount.getRoleId().equals(upmsRoleId)
        );
  }

  @Override
  public boolean anyMatch(List<UpmsRoleAccount> roleAccounts, List<SimpleEntry<Long, Long>> roleIdAndAccountIds) {
    return roleAccounts.stream()
        .anyMatch(roleAccount -> roleIdAndAccountIds.stream()
            .anyMatch(roleIdAndAccountId -> {
              Long upmsRoleId = roleIdAndAccountId.getKey();
              Long iamAccountId = roleIdAndAccountId.getValue();
              return roleAccount.getIamAccountId().equals(iamAccountId)
                  && roleAccount.getRoleId().equals(upmsRoleId);
            })
        );
  }

  @Override
  public UpmsRoleAccount build(Long upmsAppId, Long upmsRoleId, Long iamAccountId) {
    return UpmsRoleAccount.builder()
        .id(this.getNewId())
        .upmsAppId(upmsAppId)
        .roleId(upmsRoleId)
        .iamAccountId(iamAccountId)

        .updateTime(SystemClockUtils.currentTimeMillis())
        .createTime(SystemClockUtils.currentTimeMillis())
        .rowVersion(CoreConstant.DEFAULT_ROW_VERSION)
        .deleteFlag(CoreConstant.DELETE_FLAG_NOT)
        .build();
  }

  @Override
  public List<UpmsRoleAccount> getByUpmsAppIdAndIamAccountIdIn(Long upmsAppId, List<Long> iamAccountIds) {
    return this.upmsRoleAccountRepository.getByUpmsAppIdAndIamAccountIdIn(upmsAppId, iamAccountIds);
  }

  @Transactional(rollbackFor = Throwable.class)
  @Override
  public void insertNewAndDeleteByIdIn(List<UpmsRoleAccount> newUpmsRoleAccounts, List<Long> deleteUpmsRoleAccountIds) {
    if (CollectionUtils.isNotEmpty(newUpmsRoleAccounts)) {
      this.upmsRoleAccountRepository.insert(newUpmsRoleAccounts, false);
    }
    this.upmsRoleAccountRepository.deleteAllById(deleteUpmsRoleAccountIds);
  }
}
